
// 函数定义-------------------------------------------------------------------
// 函数表达式
// 也称为匿名函数
let myFunction = function () {
	console.log(1);
};

myFunction();

console.log(typeof myFunction);

// 函数有提升 用于变量声明（var）和函数声明 
// 注意：使用表达式定义的函数不会被提升。


// 自调用
let myFunction1 = function () {
	console.log(2);
}();

// 自调用一般使用这种 匿名的自调用函数 只会调用一次 就消失了
(function () {
	console.log(3);
})();


// 函数可以用做值，利用的就是函数的返回值
let myFunction2 = function () {
	return 1;
};

let a = myFunction2();
console.log(a);

// arguments.length 会返回函数被调用时收到的参数数目
// 在箭头函数中 没有arguments对象
let myFunction3 = function (a, b, c) {
	console.log(arguments.length);
};
// let myFunction3 =  (a, b, c) => {
// 	console.log(arguments.length);
// };

myFunction3(1, 2, 3, 5);

// ES6 箭头函数 vue3使用的基本都是箭头函数

// 将function关键字变成箭头

let myFunction4 =  () => {
	console.log(5);
};

myFunction4();

// 如果函数只有一个语句，并且该语句返回一个值，则可以去掉括号和 return 关键字
let myFunction5 =  () => 1;
let b = myFunction5();
console.log(b);

// 如果只有一个参数，你也可以略过括号
let myFunction6 =  a => a;
let c = myFunction6(6);
console.log(c);

// 建议写法
let myFunction7 =  (a) => {
	return a;
};


// 函数参数-------------------------------------------------------------------
// JavaScript 函数不会对参数值进行任何检查
let myFunction8 =  (a, b) => {
	console.log(a, b);
};
myFunction8(8);


// 普通类型传递值(参数的改变在函数之外是不可见的)，对象类型传递引用(对象属性的改变在函数之外是可见的)
let d = 9; 
let myFunction9 =  (d) => {
	d += 1;
	console.log(d);
};
myFunction9(d);
console.log(d);


const arr = [1, 2];
let myFunction10 =  (arr) => {
	arr[1] = 10
	console.log(arr[1]);
};
myFunction10(arr);
console.log(arr);


// 函数参数中可以有默认值
let testFunction = function(a, b = 1){
	console.log(a, b);
}

testFunction(1);

// 函数的多个参数列表( rest parameter) ...arr 是一个数组 不传递就是一个空数组 可以接收任意个参数
// 注意：1.这种参数列表只能存在一个 2.这种参数列表只能放在最后
let testFunction1 = function(a,  ...arr1){
	console.log(a, arr);
}
testFunction1(1, 2, 3);

// 函数调用-------------------------------------------------------------------
function myFunction11() {
	console.log(11);
}

myFunction11();
window.myFunction11();




// 函数闭包-------------------------------------------------------------------

// 用来实现属性私有化


// 不通过关键词 var 创建的变量总是全局的，即使它们在函数中创建
function myFunction12() {
	f = 1;
}
myFunction12();
console.log(f);


// 计数器的案例

// 第一版 问题：counter是一个全局变量，很容易造成变量的修改，但是我们需要它局部使用
/*
// 初始化计数器
var counter = 0;

// 递增计数器的函数
function add() {
  counter += 1;
}

// 调用三次 add()
add();
add();
add();

counter += 1;
// 此时计数器应该是 3
console.log(counter);

*/



// 第二版 问题：我们想到将变量变成局部变量，但是外部无法进行叠加

/*

// 初始化计数器
var counter = 0;

// 递增计数器的函数
function add() {
  var counter = 0; 
  counter += 1;
}

// 调用三次 add()
add();
add();
add();

//此时计数器应该是 3。但它是 0。
console.log(counter);


*/



// 第三版 问题：每次调用的时候 每次都会将counter进行初始化

/*
// 递增计数器的函数
function add() {
  var counter = 0; 
  counter += 1;
  return counter;
}

// 调用三次 add()
let counter = add();
counter = add();
counter = add();

//此时计数器应该是 3。但它是 1。
console.log(counter);



*/

/*
// 让变量私有化
// 所有函数都有权访问它们父级的作用域
function add() {
    var counter = 0;
    function plus() {
    	counter += 1;
    }
    plus();     
    return counter; 
}

let counter = add();
console.log(counter);


*/


// 最终版

var temp = function () {
    var counter = 0; // 1  2  3
    var temp1 = function () {
    	return counter += 1;
    }
    return temp1;
}

// 接收temp1的值（函数）
var add = temp();

add();
add();
// 接收temp1函数执行的结果
let counter = add();
console.log(counter); // 3

/*
注意：
闭包会引发内存泄露

形成闭包的条件：
1.函数的嵌套
2.子函数要引用父函数的变量
3.将子函数进行返回
*/


// 回调函数----------------------------------------------------

// 这种写法无法阻止myDisplayer执行
// function myDisplayer(some) {
//   console.log(some);
// }

// function myCalculator(num1, num2) {
//   let sum = num1 + num2;
//   myDisplayer(sum);
//   // return sum;
// }

// let result = myCalculator(5, 5);
// myDisplayer(result);
// myCalculator(5, 5)

// 回调是作为参数传递给另一个函数的函数(把函数作为参数)
// 我们调用的函数，返回来又会调用我们传进去的函数

function myDisplayer(some) {
  console.log(some);
}
function myDisplayer1(some) {
	console.log(some, 1);
}



function myCalculator(num1, num2, myCallBack) {
  let sum = num1 + num2;
  myCallBack(sum);
}

myCalculator(5, 5, myDisplayer);
myCalculator(5, 5, myDisplayer1);



let testFunction4 = function() {
		console.log(1);
}

// 传递两个参数 一个要执行的函数 另外一个超时时间
// 异步和同步
// 异步：你干你的我干我的
// 同步：你干完了 我再干
// setTimeout(testFunction4, 3000);
// console.log(2);

// setInterval() 可以指定每个间隔执行的回调函数
let a1 = setInterval(testFunction4, 3000);
console.log(2);
// clearInterval() 方法清除使用 setInterval() 方法 设置的计时器
clearInterval(a1);





